library(tidyverse) # data wrangling & plotting
library(patchwork) # multiple plot alignment
library(palmerpenguins) # Penguins dataCombining plots with patchwork in R
adapted from Abu Bakar Siddique, SLUBI, SLU
In the previous sessions, you have worked with ggplot2 to create a variety of visualizations in R. Today’s session introduces the R package patchwork, which provides a simple and intuitive way to combine multiple ggplot objects into a single figure.
During the lecture, we will see how patchwork can be used to arrange plots side by side, stack them vertically, and create more complex layouts with minimal additional code.
You can follow along during the lecture, recreate the examples, and try small modifications to the code.
In this session, we will work with the palmerpenguins dataset, which contains measurements of penguins from three species collected on islands in the Palmer Archipelago, Antarctica. The dataset includes variables such as bill length, bill depth, flipper length, body mass, and sex, and works nicely for practicing data visualization and analysis.
Required Packages
Combining two or more ggplot2 plots is a common task when creating figures. Several R packages can help with this, offering easy ways to arrange plots next to each other, adjust their relative widths and heights, or place one plot inside another as an inset. Below, you’ll find a few alternative options for combining plots.
During the session, we will create four ggplot objects:
- a scatter plot,
- a bar plot,
- a line plot, and
- a boxplot.
Using these plots, we can test how to combine different plot types with patchwork.
p <- ggplot(penguins, aes(x=flipper_length_mm, y=body_mass_g,color=species)) + geom_point()
q <- ggplot(penguins, aes(x=year, y=body_mass_g, fill=species)) + geom_bar(stat="identity")
r <- ggplot(penguins, aes(x=flipper_length_mm, y=body_mass_g,color=species)) + geom_line()
s <- ggplot(penguins, aes(x=flipper_length_mm, y=body_mass_g,color=species)) + geom_boxplot()Combining Plots: horizontally
p + q When using patchwork to combine ggplot2 plots, different operators control how the plots are arranged:
p + qadds plots to the layout and lets patchwork decide how to arrange them.p | qplaces plots next to each other in a single row (left to right).
In simple cases, p + q and p | q may look the same, but using the pipe, |, makes your layout choice explicit and easier to understand.
Combining Plots: vertically
To explicitely stack two plots on top of each other, you can use the slash /:
p / q # slashBuilding more complex figures
One of the strengths of patchwork is that simple operators can be combined to create more complex layouts. For example:
(p | q) / rHere, p and q are first placed next to each other using |. The result is then combined with r using /, which stacks r below the first row. By grouping plots with parentheses, you can control how patchwork interprets the layout.
By combining operators like |, /, and +, you can gradually build up more complex figures from simple pieces, without needing to learn a separate layout language. This makes it easy to experiment with different arrangements and clearly communicate your results:
(p | q | r) / sQuiztime: So how would the following plot look like?
p + q + r + s Adding labels to plots
Patchwork also makes it easy to add labels to your combined figures. For example:
p + q + r + s +
plot_annotation(tag_levels = 'a')This adds automatic tags (a, b, c, d) to each plot in the order they appear in the layout. These labels are useful when referring to specific panels in a report, presentation, or figure caption.
You don’t need to label each plot manually — patchwork takes care of the numbering for you.
How do you think you can change the labels from letters to numbers? To uppercase letters?
Figure titles
You can add figure titles:
Collecting legends
When you combine multiple plots, each plot may come with its own legend. This can make the final figure look repetitive or cluttered. Patchwork allows you to collect shared legends into a single guide.
The guides = "collect" option gathers matching legends from all plots and displays them only once in the combined figure. This helps keep your figure clean and easier to read.
What to watch out for:
- Legends are only collected if the aesthetics match (for example, the same variable mapped to color or fill).
- If plots use different scales or different variables for the same aesthetic, patchwork will keep separate legends.
- Small differences in how aesthetics are defined can prevent legends from being collected, even if the plots look similar.
If the legends are not collected as expected, check that the same variables and scales are used across plots.
Combine titles and collected legends
Change theme
You can change the theme of the combined plot, just like you would for an individual plot.
When you combine plots using patchwork, the operators + and & look similar but do different things when adding themes.
+ applies to a single plot (or the last plot)
The + operator in patchwork behaves the same way as in normal ggplot2:
- It adds layers, scales, or themes to one plot
- When used in a patchwork expression, it usually affects only the plot it is directly attached to.
p1 + theme_minimal()
Here, theme_minimal() is applied only to p1.
In a patchwork layout:
(p1 | p2) + theme_minimal()
The theme is applied only to the combined patchwork object, but not propagated to all individual plots in a consistent way. This often leads to confusion or unexpected results.
& applies to all plots in patchwork to make global styling explicit
- The
&operator is specific to patchwork. - It applies a theme (or other ggplot settings) to every plot in the patchwork.
- It is designed specifically for global styling.
(p1 | p2) & theme_minimal()
Here, theme_minimal() is applied to both p1 and p2.
This is the preferred way to apply a common theme when working with multiple plots.
Abu’s script for Journal: BMC
p + q + r + s +
plot_annotation(tag_levels = list(c('a','c','b','d'))) +
plot_layout(widths = c(2, 2)) &
theme(legend.position = "right",
legend.title = element_text(size = 10),
legend.text = element_text(size = 8),
legend.key.size = unit(0.2, 'cm'),
plot.tag = element_text(size = 14,face = 'bold')) Adding inset plots
Patchwork also allows you to place one plot inside another plot as an inset. This can be useful when you want to highlight a subset of the data or show a related view without creating a separate panel.
p + inset_element(q, 0.01, 0.59, 0.5, 0.9)In this example, q is added as an inset inside plot p. The four numbers define the position of the inset, as proportions of the main plot area:
- the first two values control the horizontal placement (left and right),
- the last two values control the vertical placement (bottom and top).
By adjusting these values, you can move and resize the inset plot to fit your figure.
Does patchwork work with base R plots?
No. Patchwork only works with ggplot2 plots.
This is because patchwork combines plots by working with ggplot objects behind the scenes.
Base R plots (created with functions like plot(), hist(), or boxplot()) are drawn directly to the graphics device and are not stored as objects in the same way. Because of this, patchwork cannot rearrange or combine them.
Workaround:
We said that patchwork only works with ggplot2 plots. That is mostly true — but there is a useful exception.
old_par <- par(mar = c(0, 0, 0, 0), mgp = c(1, 0.25, 0),
bg = NA, cex.axis = 0.75, las = 1, tcl = -0.25)
plot_object <- p + ~plot(penguins$flipper_length_mm, penguins$body_mass_g, main = 'Base plot')
plot_objectIn this example, the base R plot is wrapped inside ~ (a formula). This tells patchwork to capture the output of the base plot and treat it as a graphical object, rather than a regular base plot.
So patchwork is not combining base plots directly. Instead, it is embedding the base plot as an element inside a patchwork layout.
- The base plot is not a
ggplotobject and cannot be modified withggplot2layers. - You cannot easily collect legends or align axes between base plots and ggplots.
- This approach is useful for quick comparisons or demonstrations, but mixing plot systems can be limiting.
Saving plots
Combined plots created with patchwork can be saved in the same way as regular ggplot2 plots. Since a patchwork object behaves like a ggplot object, you can use ggsave():
ggsave("plot.tiff",plot_object,height=170,width=85,units="mm",dpi=300,type="cairo", device=tiff)
# https://bmcmicrobiol.biomedcentral.com/submission-guidelines/preparing-your-manuscript#preparing+figuresThis is the recommended approach for saving ggplot- and patchwork-based figures, especially for publication-quality output.
It is also possible to save ggplot objects using base R graphics devices:
png("plot.tiff",height=170,width=85,units="mm",res=300)
print(p)
dev.off()Here, print(p) is required to draw the ggplot object to the graphics device.
ggsave()automatically uses the size and resolution you specify and is usually the easiest option.- When using base graphics devices (
png(),tiff()), you must callprint()for ggplot or patchwork objects. - Patchwork figures are saved as a single plot, just like any other ggplot object.
- Always check journal or report guidelines for required file formats, sizes, and resolution.